<template>
    <div :class="{ 'show': show }" class="header-search ">
        <svg-icon class-name="search-icon" icon-class="search" @click.stop="click"/>
        <el-select
                ref="headerSearchSelectRef"
                v-model="search"
                :remote-method="querySearch"
                filterable
                default-first-option
                remote
                placeholder="Search"
                class="header-search-select"
                @change="change"
        >
            <el-option v-for="option in options" :key="option.item.path" :value="option.item"
                       :label="option.item.title.join(' > ')"/>
        </el-select>
    </div>
</template>

<script setup>
    import Fuse from 'fuse.js'
    import {getNormalPath} from '@/utils/ruoyi'
    import {isHttp} from '@/utils/validate'
    import usePermissionStore from '@/store/modules/permission'

    const search = ref('');
    const options = ref([]);
    const searchPool = ref([]);
    const show = ref(false);
    const fuse = ref(undefined);
    const headerSearchSelectRef = ref(null);
    const router = useRouter();
    const routes = computed(() => usePermissionStore().routes);

    function click() {
        show.value = !show.value
        if (show.value) {
            headerSearchSelectRef.value && headerSearchSelectRef.value.focus()
        }
    };

    function close() {
        headerSearchSelectRef.value && headerSearchSelectRef.value.blur()
        options.value = []
        show.value = false
    }

    function change(val) {
        const path = val.path;
        const query = val.query;
        if (isHttp(path)) {
            // http(s):// 路径新窗口打开
            const pindex = path.indexOf("http");
            window.open(path.substr(pindex, path.length), "_blank");
        } else {
            if (query) {
                router.push({path: path, query: JSON.parse(query)});
            } else {
                router.push(path)
            }
        }

        search.value = ''
        options.value = []
        nextTick(() => {
            show.value = false
        })
    }

    function initFuse(list) {
        fuse.value = new Fuse(list, {
            shouldSort: true,
            threshold: 0.4,
            location: 0,
            distance: 100,
            minMatchCharLength: 1,
            keys: [{
                name: 'title',
                weight: 0.7
            }, {
                name: 'path',
                weight: 0.3
            }]
        })
    }

    // Filter out the routes that can be displayed in the sidebar
    // And generate the internationalized title
    function generateRoutes(routes, basePath = '', prefixTitle = []) {
        let res = []

        for (const r of routes) {
            // skip hidden router
            if (r.hidden) {
                continue
            }
            const p = r.path.length > 0 && r.path[0] === '/' ? r.path : '/' + r.path;
            const data = {
                path: !isHttp(r.path) ? getNormalPath(basePath + p) : r.path,
                title: [...prefixTitle]
            }

            if (r.meta && r.meta.title) {
                data.title = [...data.title, r.meta.title]

                if (r.redirect !== 'noRedirect') {
                    // only push the routes with title
                    // special case: need to exclude parent router without redirect
                    res.push(data)
                }
            }
            if (r.query) {
                data.query = r.query
            }

            // recursive child routes
            if (r.children) {
                const tempRoutes = generateRoutes(r.children, data.path, data.title)
                if (tempRoutes.length >= 1) {
                    res = [...res, ...tempRoutes]
                }
            }
        }
        return res
    }

    function querySearch(query) {
        if (query !== '') {
            options.value = fuse.value.search(query)
        } else {
            options.value = []
        }
    }

    onMounted(() => {
        searchPool.value = generateRoutes(routes.value);
    })

    watchEffect(() => {
        searchPool.value = generateRoutes(routes.value)
    })

    watch(show, (value) => {
        if (value) {
            document.body.addEventListener('click', close)
        } else {
            document.body.removeEventListener('click', close)
        }
    })

    watch(searchPool, (list) => {
        initFuse(list)
    })
</script>

<style lang='scss' scoped>
    .header-search {
        font-size: 0 !important;

        .search-icon {
            cursor: pointer;
            font-size: 18px;
            vertical-align: middle;
        }

        .header-search-select {
            font-size: 18px;
            transition: width 0.2s;
            width: 0;
            overflow: hidden;
            background: transparent;
            border-radius: 0;
            display: inline-block;
            vertical-align: middle;

            :deep(.el-input__inner) {
                border-radius: 0;
                border: 0;
                padding-left: 0;
                padding-right: 0;
                box-shadow: none !important;
                border-bottom: 1px solid #d9d9d9;
                vertical-align: middle;
            }
        }

        &.show {
            .header-search-select {
                width: 210px;
                margin-left: 10px;
            }
        }
    }
</style>